from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

from werkzeug.routing import BaseConverter
from config import config
from exceptions import ParamException, RequiredException

import uuid


db = SQLAlchemy()
login_manager = LoginManager()


def create_app(config_name):
    app = Flask(__name__)

    app.config.from_object(config[config_name])

    db.init_app(app)
    login_manager.init_app(app)

    from models import User

    @login_manager.user_loader
    def load_user(userid):
        return User.query.filter_by(id=userid).first()

    login_manager.login_view = '/login'


    class RegexConverter(BaseConverter):
        def __init__(self, url, *args):
            super().__init__(url)
            self.regex = args[0]


    app.url_map.converters['regex'] = RegexConverter

    from auth.views import auth as auth_blueprint, register as auth_register
    from front.views import front as front_blueprint, register as front_register
    from manage.views import manage as manage_blueprint, register as manage_register

    auth_register()
    front_register()
    manage_register()

    app.register_blueprint(auth_blueprint)
    app.register_blueprint(front_blueprint)
    app.register_blueprint(manage_blueprint)

    return app


def generate_id():
    return str(uuid.uuid4()).replace('-', '')


def get_param(name, type='string', required=True, default=None, max_length=None, min_length=None):
    if request.method == 'GET':
        data = request.args
    elif request.method == 'POST':
        data = request.form
    if type == 'string':
        if required:
            param = data.get(name, None)
            if not param:
                raise RequiredException('{0} is required'.format(name))
        else:
            param = data.get(name, default)
        if max_length:
            if len(str(param)) > max_length:
                raise ParamException('{0} max length is {1}'.format(name, max_length))
        if min_length:
            if len(str(param)) < min_length:
                raise ParamException('{0} min length is {1}'.format(name, min_length))
    return param